/**
 * 
 */
package com.skivingcloud.workflow.controller;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.activiti.bpmn.model.StartEvent;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.ProcessDefinition;
import org.apache.commons.io.IOUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.log.NullLogChute;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.skivingcloud.admin.annotation.ModifyAnnotaionFactory;
import com.skivingcloud.admin.annotation.UserOperateLog;
import com.skivingcloud.admin.feignclient.FSysOrgService;
import com.skivingcloud.admin.sys.entity.User;
import com.skivingcloud.admin.utils.UserUtil;
import com.skivingcloud.common.exception.BusinessException;
import com.skivingcloud.common.utils.PageUtils;
import com.skivingcloud.common.utils.R;
import com.skivingcloud.common.utils.TreeUtils;
import com.skivingcloud.workflow.conf.UrlConstant;
import com.skivingcloud.workflow.entity.ProcessVO;
import com.skivingcloud.workflow.entity.Strategy;
import com.skivingcloud.workflow.service.IDepolymentInfoService;
import com.skivingcloud.workflow.service.IStrategyService;
import com.skivingcloud.workflow.service.ModelService;

/**
 * 流程模型设计
 * @author hushouquan
 *
 */
@RestController
@RequestMapping("/workflow")
public class ModelController {
	protected static final Logger log = LoggerFactory.getLogger(ModelController.class);
	
	@Autowired
    private ModelService modelService;
	@Autowired
	private IStrategyService strategyService;
	@Autowired
	private FSysOrgService fSysOrgService;
	@Autowired
    private RepositoryService repositoryService;
	@Autowired
    private IDepolymentInfoService depolymentInfoService;
	
	/**
	 * 查询模型列表
	 * @param params
	 * @return
	 */
	@GetMapping("/model/list")
    public R list(@RequestParam Map<String, Object> params) {
		User user = UserUtil.getUser();
		PageUtils pageUtil = modelService.list(params, user);
		return R.ok().put("page", pageUtil);
	}
	
	/**
	 * 初始化一个空模型
	 * @param response
	 * @return
	 * @throws Exception
	 */
	@GetMapping("/model/add")
	public R newModel(HttpServletResponse response) throws Exception {
		User user = UserUtil.getUser();
		String id = modelService.newModel(user);
		return R.ok().put("id", id);
	}
	
	/**
	 * 根据id加载模型数据json
	 * @param modelId
	 * @return
	 */
	@GetMapping(value = "/model/{modelId}/json")
    public ObjectNode getEditorJson(@PathVariable String modelId) {
        ObjectNode modelNode = null;
        try {
			modelNode = modelService.getEditorJson(modelId);
		} catch (Exception e) {
			 log.error("Error creating model JSON", e);
             throw new BusinessException("Error creating model JSON", e);
		}
        return modelNode;// R.ok().put("modelNode", modelNode);
    }
	
	/**
	 * 根据id加载页面
	 * @param request
	 * @param response
	 * @param id
	 */
	@RequestMapping("/model/toModelerPage/{id}")
    public void toModelerPage(HttpServletRequest request, HttpServletResponse response, @PathVariable String id) {
        try {
            VelocityEngine ve = new VelocityEngine();
            ve.setProperty(Velocity.RESOURCE_LOADER, "class");
            ve.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
            ve.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, new NullLogChute());
            ve.init();
            VelocityContext context = new VelocityContext();
            context.put("contextPath", request.getContextPath() + UrlConstant.WEB_WF_URL);
            context.put("modelId", id);
            response.setContentType("text/html");
            response.setCharacterEncoding("utf-8");
            Template template = ve.getTemplate("static/modeler.html", "utf-8");
            ve.setProperty("modelId", id);
            PrintWriter writer = response.getWriter();
            template.merge(context, writer);
            writer.close();
        } catch (IOException e) {
        	 log.error("Error toModelerPage", e);
        }
    }
	
	/**
	 * 加载页面，新增
	 * @param request
	 * @param response
	 */
	@RequestMapping("/model/toModelerPageNew")
    public void toModelerPageNew(HttpServletRequest request, HttpServletResponse response) {
        try {
            VelocityEngine ve = new VelocityEngine();
            ve.setProperty(Velocity.RESOURCE_LOADER, "class");
            ve.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
            ve.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, new NullLogChute());
            ve.init();
            VelocityContext context = new VelocityContext();
            context.put("contextPath", request.getContextPath() + UrlConstant.WEB_WF_URL);
            context.put("modelId", "");
            response.setContentType("text/html");
            response.setCharacterEncoding("utf-8");
            Template template = ve.getTemplate("static/modeler.html", "utf-8");
            ve.setProperty("modelId", "");
            PrintWriter writer = response.getWriter();
            template.merge(context, writer);
            writer.close();
//			 response.sendRedirect(request.getContextPath() + "/modeler.html?modelId=" + id);
        } catch (IOException e) {
        	 log.error("Error toModelerPage", e);
        }
    }
	
	@GetMapping("/model/deleteNone/{modelId}")
    public R deleteNoneModel(@PathVariable("modelId") String modelId) {
		try {
			modelService.deleteNoneModel(modelId);
			return R.ok().put("msg", "success");
		} catch (Exception e) {
			log.error("Error deleteNone", e);
			return R.error("Error deleteNone");
		}
    }
	
	/**
	 * 删除一个模型
	 * @param id
	 * @return
	 */
	@UserOperateLog(module = "工作流", methods = "remove", description = "删除模型")
    @GetMapping("/model/delete/{id}")
    public R remove(@PathVariable("id") String id) {
        try {
        	modelService.deleteModel(id);
			return R.ok();
		} catch (Exception e) {
			log.error("删除模型失败", e);
			return R.error("删除失败");
		}
    }
	
	/**
	 * 加载设计页面信息
	 * @return
	 */
	@RequestMapping(value = "/editor/stencilset", method = RequestMethod.GET, produces = "application/json;charset=utf-8")
    @ResponseBody
    public String getStencilset() {
        InputStream stencilsetStream = this.getClass().getClassLoader().getResourceAsStream("stencilset.json");
        try {
            return IOUtils.toString(stencilsetStream, "utf-8");
        } catch (Exception e) {
            throw new ActivitiException("Error while loading stencil set", e);
        }
    }
	
	/**
	 * 查询找人策略
	 * @return
	 */
	@GetMapping("/model/strategyOption")
    public List<Strategy> all(){
		List<Strategy> result= strategyService.select(new Strategy());
		return result;
    }
	
	/**
	 * 获取树形机构
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/model/treeStationList")
	@ResponseBody
	public List<TreeUtils> treeStationList() throws Exception{
		User user = UserUtil.getUser();
		List<TreeUtils> listTree = fSysOrgService.treeStationListIconFnId(user.getTenantId());
		return listTree;
	}
	
	/**
     * 获取最新版的流程定义
     * @param params
     * @return
     * @throws Exception
     */
    @GetMapping (value = "/model/processOption")
    public List<ProcessVO> processOption (@RequestParam Map<String, Object> params) throws Exception{
        List<ProcessDefinition> processDefinitionList = modelService.getProcessOption();
        List<ProcessVO> processVOs=new ArrayList<ProcessVO>();
        for(ProcessDefinition processDefinition:processDefinitionList) {
            processVOs.add(new ProcessVO(processDefinition));
        }
        return processVOs;
    }
    
    /**
     * 修改模型
     * @param modelId
     * @param name
     * @param description
     * @param json_xml
     * @param svg_xml
     */
    @UserOperateLog(module = "工作流", methods = "saveModel", description = "修改模型", functionNo = "104007")
    @RequestMapping(value = "/model/{modelId}/save", method = RequestMethod.PUT)
    @ResponseStatus(value = HttpStatus.OK)
    @ResponseBody
    public void saveModel(@PathVariable String modelId, String name, String description, String json_xml,
                          String svg_xml) {
        ModifyAnnotaionFactory.newInstance().ModifyAnnotation(getClass(), UserOperateLog.class, "saveModel", "bussid", modelId, String.class, String.class, String.class, String.class, String.class);
        try {
            modelService.saveModel(modelId, name, description, json_xml, svg_xml);
        } catch (BusinessException e) {
            log.error(e.getMessage(), e);
            throw new ActivitiException(e.getMessage(), e);
        } catch (Exception e) {
            log.error("Error saving model", e);
            throw new ActivitiException("Error saving model", e);
        }
    }
    
    /**
     * 发布模型
     * @param id
     * @return
     * @throws Exception
     */
    @UserOperateLog(module = "工作流", methods = "deploy", description = "发布模型", functionNo = "104005")
    @PostMapping("/model/deploy/{id}")
    public R deploy(@PathVariable("id") String id) throws Exception {
        ModifyAnnotaionFactory.newInstance().ModifyAnnotation(getClass(), UserOperateLog.class, "deploy", "bussid", id, String.class);
        try {
        	User user = UserUtil.getUser();
            modelService.deploy(id, user);
            return R.ok();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return R.error(e.getMessage());
        }
    }
    
    /**
     * 导出流程文件
     * @param deploymentId
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/model/export/{deploymentId}")
    public R resourceRead(@PathVariable String deploymentId, HttpServletRequest request, HttpServletResponse response) {
    	OutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();

            if (processDefinition != null) {
                InputStream resourceAsStream = modelService.resourceRead(processDefinition.getId(), "xml", processDefinition);
                byte[] b = new byte[1024];
                int len = -1;
                // 配置文件下载
                response.setHeader("content-type", "application/octet-stream");
                response.setContentType("application/octet-stream");
                // 下载文件能正常显示中文
                response.setHeader("Content-Disposition", "attchement;filename=" + URLEncoder.encode(processDefinition.getTenantId() + "@" + processDefinition.getResourceName(), "UTF-8"));
                while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
                    outputStream.write(b, 0, len);
                }
            } else {
                return R.error();
            }

        } catch (Exception e) {
            e.printStackTrace();
            return R.error();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.flush();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
    
    /**
     * 根据部署id获取流程定义
     * @param deploymentId
     * @return
     */
    @GetMapping (value = "/model/getProcessDefinition/{deploymentId}")
    public R getProcessDefinition(@PathVariable String deploymentId) {
    	try {
        	User user = UserUtil.getUser();
        	ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
        	ProcessVO vo = new ProcessVO(processDefinition);
            return R.ok().put("def", vo);
        } catch (Exception e) {
        	log.error("获取流程历史版本失败", e);
            return R.error(e.getMessage());
        }
    }
    
    /**
     * 流程历史版本查询
     * @param params
     * @return
     */
    @GetMapping("/model/getProcessDefinitionHis")
    PageUtils getProcessDefinitionHis(@RequestParam Map<String, Object> params) {
        PageUtils pageUtils = depolymentInfoService.queryPage(params);
        return pageUtils;
    }
    
    /**
     * 流程导入
     * @param request
     * @return
     */
    @UserOperateLog(module = "工作流", methods = "deploy", description = "导入流程")
    @PostMapping("/model/uploadModelFile")
    public R uploadModelFile(HttpServletRequest request) {
        StandardServletMultipartResolver resolver = new StandardServletMultipartResolver();
        MultipartHttpServletRequest mhr = resolver.resolveMultipart(request);
        List<MultipartFile> files = mhr.getFiles("file");
        String message = "";
        User user = UserUtil.getUser();
        try {
        	modelService.improtDeploy(files, user);
        } catch (BusinessException e){
            return R.error(e.getMessage());
        } catch (Exception e) {
            log.error("部署失败", e);
            return R.error("部署失败！");
        }
        return R.ok(message);
    }
    
    /**
     * 获取第一个节点信息
     * @param deploymentId
     * @return
     */
    @GetMapping("/model/getDefFirstNode/{processKey}")
    PageUtils getDefFirstNode(@PathVariable String deploymentId) {
        return null;
    }
    
    /**
     * 根据流程编码获取流程开始节点信息
     * @param defKey 流程编码
     * @return
     */
    @GetMapping("/model/getModelStartNodeInfo/{defKey}")
    public R getModelStartNodeInfo(@PathVariable("defKey") String defKey){
        StartEvent flowElement = null;
        try {
            flowElement = modelService.getModelStartNodeInfo(defKey);
            return R.ok().put("flowElement", flowElement);
        } catch (BusinessException e) {
            log.error(e.getMessage(), e);
            return  R.error(e.getMessage());
        } catch (Exception e) {
            log.error("获取流程节点信息失败", e);
            return  R.error("获取流程节点信息失败");
        }
    }
    
    /**
     * 流程名称查询
     * <p>查询所有最新版本的流程名称</p>
     *
     * @return
     */
    @GetMapping("/model/processDefNames")
    public R getProcessNames() {
        try {
        	User user = UserUtil.getUser();
            List<ProcessVO> processVOList = modelService.getProcessNameList(user.getTenantId());
            return R.ok().put("data", processVOList);
        } catch (Exception e) {
            return R.error();
        }

    }
}
